import os
import json
from typing import List
from types import FunctionType

import ui

def is_valid_filename(filename):
    """
    判断文件名是否合法。
    """
    try:
        os.path.basename(filename)
        return True
    except:
        return False

class Save:
    I = None
    def __init__(self) -> None:
        Save.I = self
        self.prepareAppdata()

        self.data = None
        self.global_data = None

        self.saveFuncs = []
        self.readFuncs = []
        self.saveGlobalFuncs = []
        self.readGlobalFuncs = []

    def read(self) -> None:
        if type(ui.UI.ui) == ui.Desktop: self.readFromLocal()

    def save(self) -> None:
        if type(ui.UI.ui) == ui.Desktop: self.saveToLocal()

    def prepareAppdata(self) -> None:
        self.appdata = appdata = os.getenv("APPDATA")
        
        td = os.path.realpath(os.path.join(
            appdata, "./text_dungeon/"
        ))

        os.makedirs(td,exist_ok=True)

        self.save_path = save_path = os.path.realpath(os.path.join(
            td, "./save.json"
        ))

        self.global_path = global_path = os.path.realpath(os.path.join(
            td, "./global.json"
        ))

        self.monument_path = monument_path = os.path.realpath(os.path.join(
            td, "./monument/"
        ))

    def readFromLocal(self) -> bool:
        """
        存档存在返回False,
        否则是True
        """
        if os.path.exists(self.save_path): # 存档存在
            with open(self.save_path,"r",encoding="utf-8") as f:
                self.data = json.load(f)
            return False
        else:
            self.data = {}
            return True
        
    def readGlobalFromLocal(self) -> bool:
        if os.path.exists(self.global_path):
            with open(self.global_path,"r",encoding="utf-8") as f:
                    self.global_data = json.load(f)
            return False
        else:
            self.global_data = {} 
            return True

    def saveToLocal(self) -> None:
        with open(self.global_path,"w+",encoding="utf-8") as f:
            f.write(json.dumps(self.global_data,ensure_ascii=False,indent=4))

        if not self.data: return

        with open(self.save_path,"w+",encoding="utf-8") as f:
            f.write(json.dumps(self.data,ensure_ascii=False,indent=4))

    def moveSaveToMonument(self, name:str) -> bool:
        """
        打完后把存档保存纪念
        """
        self.doSaveFuncs()
        os.makedirs(self.monument_path,exist_ok=True)

        pth = os.path.realpath(os.path.join(
            self.monument_path,"./{}.json".format(name)
        ))

        if os.path.exists(pth) or not is_valid_filename(name):
            return False
        
        with open(os.path.realpath(os.path.join(
            self.monument_path,"./{}.json".format(name)
        )),"w+") as f:
            f.write(json.dumps(self.data))

        os.remove(self.save_path)
        return True
            

    def registerSave(self, saveObjects: List[object]) -> None:
        """
        传入的saveObjects内的对象可以有toSave函数和fromSave函数，
        toSave是这样的:
        def toSave(save:Save) -> None:
            # 向save.data加入自己的项

        fromSave是这样的:
        def fromSave(save:Save) -> None:
            # 从save.data里读取需要的项
        还可以有toGlobal和fromGlobal
        差不多, 主要是这两个存取的应该是全局存档，而不是一把的存档，请读取save.global_data,也是字典
        """
        for i in saveObjects:
            if hasattr(i,"toSave"):
                self.saveFuncs.append(i.toSave)
            if hasattr(i,"fromSave"):
                self.readFuncs.append(i.fromSave)
            if hasattr(i,"toGlobal"):
                self.saveGlobalFuncs.append(i.toGlobal)
            if hasattr(i,"fromGlobal"):
                self.readGlobalFuncs.append(i.fromGlobal)

    def doSaveFuncs(self) -> None:
        for i in self.saveFuncs:
            i(self)

    def doReadFuncs(self) -> None:
        for i in self.readFuncs:
            i(self)

    def doSaveGlobalFuncs(self) -> None:
        for i in self.saveGlobalFuncs:
            i(self)

    def doReadGlobalFuncs(self) -> None:
        for i in self.readGlobalFuncs:
            i(self)